import { MinusCircleOutlined, PlusCircleOutlined } from '@ant-design/icons';
import type { TableProps } from 'antd';
import { Button, Table } from 'antd';
import React, {
  forwardRef,
  useCallback,
  useEffect,
  useImperativeHandle,
  useMemo,
  useRef,
  useState,
} from 'react';
import type { FormInstance } from 'ym-design';
import EditTableCell from './EditTableCell';
import EditTableRow from './EditTableRow';
import { useFormInstanceObserves } from './hooks/useFormInstanceObserves';
import type {
  ActionRefType,
  ValueTypeProps,
  YmEditTableColumnType,
  YmEditTableProps,
} from './interface';

import type { DragEndEvent } from '@dnd-kit/core';
import { DndContext } from '@dnd-kit/core';
import { restrictToVerticalAxis } from '@dnd-kit/modifiers';
import {
  arrayMove,
  SortableContext,
  verticalListSortingStrategy,
} from '@dnd-kit/sortable';

const YmEditTable = forwardRef<ActionRefType, YmEditTableProps>(
  (props, ref) => {
    const {
      value,
      readonly,
      columns,
      rowKey = 'editRowKey',
      max,
      onChange,
      onRowValuesChange,
      hideAddBtn = false,
      formInitialValues,
      dragAndDrop = false,
      ...restProps
    } = props;

    const fieldNamesRef = useRef<string[]>([]);
    const [dataSource, setDataSource] = useState<Record<string, any>[]>([]);
    const countRef = useRef<number>(0); //作为rowKey的值

    // 处理value,变为受控
    useEffect(() => {
      const newValue = (value || []).map((valItem) => {
        if (valItem[rowKey] === undefined || valItem[rowKey] === null) {
          valItem[rowKey] = countRef.current++;
        }
        return valItem;
      });
      setDataSource(newValue);
    }, [value]);

    // 新增
    const handleAdd = useCallback<(currRowKey?: string) => void>(
      (currRowKey) => {
        const rowIndex = dataSource.findIndex(
          (data) => data[rowKey] === currRowKey,
        );
        const defaultRecord = fieldNamesRef.current.reduce(
          (
            prev: Record<string, any>,
            curr: string,
            index: number,
            array: string[],
          ) => {
            prev[curr] = undefined;
            return prev;
          },
          {},
        );
        defaultRecord[rowKey] = countRef.current++;
        let newValue: Record<string, any>[] = [];
        if (
          typeof rowIndex === 'number' &&
          rowIndex >= 0 &&
          rowIndex < dataSource.length
        ) {
          const sliceIndex = rowIndex + 1;
          newValue = [
            ...dataSource.slice(0, sliceIndex), //slice >= <
            defaultRecord,
            ...dataSource.slice(sliceIndex),
          ];
        } else {
          newValue = [...dataSource, defaultRecord];
        }
        const end =
          typeof max === 'number'
            ? Math.min(max, newValue.length)
            : newValue.length;
        newValue = newValue.slice(0, end);
        onChange?.(newValue);
      },
      [dataSource, max],
    );

    //删除
    const handleDelete = useCallback<(currRowKey: string) => void>(
      (currRowKey) => {
        const newValue = dataSource.filter(
          (data) => data[rowKey] !== currRowKey,
        );
        onChange?.(newValue);
        countRef.current--;
      },
      [dataSource],
    );

    //编辑
    const handleRowValuesChange = (
      rowIndex: number,
      newRecord: Record<string, any>,
    ) => {
      onRowValuesChange?.(rowIndex, newRecord);
      dataSource[rowIndex] = { ...dataSource[rowIndex], ...newRecord };
      onChange?.([...dataSource]);
    };

    //2. 存储 row- FormInstance
    const {
      addFormInstance,
      removeFormInstance,
      validateObservers,
      formResetObservers,
      getFormInstances,
    } = useFormInstanceObserves();

    const getColOperation = useCallback<
      (text: any, record: any, valueType?: ValueTypeProps) => React.ReactElement
    >(
      (text, record, valueType) => {
        const { operationProps = {} } = valueType || {};
        const { addBtn = {}, deleteBtn = {} } = operationProps;
        const { hidden: addBtnHidden, ...addBtnRestProps } = addBtn;
        const { hidden: deleteBtnHidden, ...deleteBtnRestProps } = deleteBtn;
        const showAddBtn =
          !addBtnHidden &&
          (typeof max !== 'number' ||
            (typeof max === 'number' && max > (dataSource.length || 0)));
        return (
          <>
            {showAddBtn && (
              <Button
                type="link"
                size="small"
                icon={<PlusCircleOutlined />}
                {...addBtnRestProps}
                onClick={() => {
                  handleAdd(record[rowKey]);
                }}
              />
            )}
            {!deleteBtnHidden && (
              <Button
                type="link"
                size="small"
                icon={<MinusCircleOutlined />}
                {...deleteBtnRestProps}
                onClick={() => {
                  handleDelete(record[rowKey]);
                }}
              />
            )}
          </>
        );
      },
      [readonly, columns, max, dataSource],
    );

    //3.处理columns
    const newColumns = useMemo<YmEditTableColumnType[]>(() => {
      if (readonly) return columns;
      function getNewColumn(col: YmEditTableColumnType): YmEditTableColumnType {
        const tableColumn = {
          ...col,
          children: Array.isArray(col.children)
            ? col.children.map(getNewColumn)
            : undefined,
        };
        const {
          title,
          editable,
          dataIndex,
          formItemProps = {},
          valueType,
        } = tableColumn;
        if (dataIndex === 'operation') {
          //操作列
          return {
            title,
            dataIndex,
            width: 80,
            key: 'operation',
            render: (text, record) =>
              getColOperation(text, record, valueType as ValueTypeProps),
          };
        }

        if (!editable) {
          return tableColumn;
        }
        const currFormItemProps = {
          name: dataIndex,
          ...formItemProps,
        };
        tableColumn.onCell = (record: any, rowIndex?: number): any => ({
          //给单元格添加属性
          editable,
          record,
          rowIndex,
          formItemProps: currFormItemProps,
          valueType,
        });
        // 可编辑单元格存储表单name字段；
        if (fieldNamesRef.current.indexOf(dataIndex as string) === -1) {
          fieldNamesRef.current.push(dataIndex as string);
        }
        return tableColumn;
      }

      const tempNewColumns = columns.map(getNewColumn);
      if (dragAndDrop && !readonly) {
        tempNewColumns.unshift({ key: 'sort', width: 40, align: 'center' });
      }

      return tempNewColumns;
    }, [readonly, columns, max, dataSource, dragAndDrop]);

    //设置当前行数据
    const setRowsData = (rowData: Record<string, any>) => {
      const currRowKey = rowData[rowKey];
      if (currRowKey !== undefined && currRowKey !== null) {
        const currRowFormInstance = getFormInstances(currRowKey);
        if (currRowFormInstance) {
          // const recordData = fieldNamesRef.current.reduce((prev: Record<string, any>, curr: string, index: number, array: string[]) => {
          //   prev[curr] = rowData[curr];
          //   return prev;
          // }, {});
          (currRowFormInstance as FormInstance).setFieldsValue(rowData);
          const currRowData = (
            currRowFormInstance as FormInstance
          ).getFieldsValue('all');
          const newDataSource = dataSource.map((data) => {
            if (data[rowKey] === currRowKey) {
              return currRowData;
            }
            return data;
          });
          onChange?.(newDataSource);
        }
      }
    };

    //重置
    const handleReset = (currRowKey?: string) => {
      if (fieldNamesRef.current && !fieldNamesRef.current.length) return;
      const rowsDatas = formResetObservers(fieldNamesRef.current, currRowKey);
      let newDataSource: Record<string, any>[] = dataSource;
      if (Array.isArray(rowsDatas)) {
        newDataSource = dataSource.map((data) => {
          const currRowData = rowsDatas.find(
            (rowData) => rowData[rowKey] === data[rowKey],
          );
          if (currRowData) {
            return { ...currRowData };
          }
        });
      } else if (typeof rowsDatas === 'object') {
        newDataSource = dataSource.map((data) => {
          if (data[rowKey] === rowsDatas[rowKey]) {
            return { ...rowsDatas };
          }
          return data;
        });
      }
      onChange?.(newDataSource);
    };

    useImperativeHandle(ref, () => ({
      setRowsData,
      handleValidate: validateObservers,
      handleReset,
    }));

    // 4.table
    const tableConfig: TableProps<any> = {
      size: 'small',
      pagination: false,
      tableLayout: 'fixed',
      scroll: { x: '100%' },
      bordered: true,
      rowKey,
      columns: newColumns,
      rowClassName: () => 'editable-row',
      dataSource,
      onRow: (record, index): any => {
        //给行添加属性
        return {
          dragAndDrop,
          record,
          index,
          rowKey,
          fieldNames: fieldNamesRef.current,
          formInitialValues,
          onRowValuesChange: handleRowValuesChange,
          addFormInstance,
          removeFormInstance,
        };
      },
      components: {
        body: {
          row: EditTableRow,
          cell: EditTableCell,
        },
      },
      ...restProps,
    };

    const onDragEnd = ({ active, over }: DragEndEvent) => {
      if (active.id !== over?.id) {
        const activeIndex = dataSource.findIndex(
          (i) => i[rowKey] === active.id,
        );
        const overIndex = dataSource.findIndex((i) => i[rowKey] === over?.id);
        const newDataSource = arrayMove(dataSource, activeIndex, overIndex);
        onChange?.(newDataSource);
      }
    };

    let tableDom = <Table {...tableConfig} />;
    if (dragAndDrop && !readonly) {
      tableDom = (
        <DndContext modifiers={[restrictToVerticalAxis]} onDragEnd={onDragEnd}>
          <SortableContext
            // rowKey array
            items={dataSource.map((data) => data[rowKey])}
            strategy={verticalListSortingStrategy}
          >
            <Table {...tableConfig} />
          </SortableContext>
        </DndContext>
      );
    }

    return (
      <div className="ym-edit-table-content">
        {tableDom}
        {!hideAddBtn &&
          !readonly &&
          (typeof max !== 'number' ||
            (typeof max === 'number' && max > (dataSource.length || 0))) && (
            <Button
              type="dashed"
              block
              onClick={(e) => {
                handleAdd();
              }}
              style={{ marginTop: 8 }}
            >
              <i className="iconfont lmweb-plus" />
              新增
            </Button>
          )}
      </div>
    );
  },
);

export default YmEditTable;
